package ohc.login

import net.fabricmc.loader.api.FabricLoader
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.server.MinecraftServer
import net.minecraft.server.world.ServerWorld
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.util.WorldSavePath
import net.minecraft.world.World
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit

/**
 * 存档备份与回档管理器
 */
object BackupManager {
    
    private val executor = Executors.newSingleThreadExecutor { r ->
        Thread(r, "OHC-Backup-Thread").apply { isDaemon = true }
    }
    
    private val scheduler: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor { r ->
        Thread(r, "OHC-AutoBackup-Scheduler").apply { isDaemon = true }
    }
    
    private val backupDir: File by lazy {
        FabricLoader.getInstance().gameDir.resolve("ohc_backups").toFile().also { it.mkdirs() }
    }
    
    private val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss")
    
    private const val SYSTEM_BACKUP_NAME = "system"
    
    private var server: MinecraftServer? = null
    
    private var scheduledTask: java.util.concurrent.ScheduledFuture<*>? = null
    
    /**
     * 初始化自动存档调度器
     */
    fun init(server: MinecraftServer) {
        this.server = server
        scheduleAutoBackup()
        Ohc_login.logger.info("自动存档调度器已启动，每天凌晨0点执行")
    }
    
    /**
     * 调度每天凌晨0点的自动存档
     */
    private fun scheduleAutoBackup() {
        if (!Config.autoBackupEnabled) {
            Ohc_login.logger.info("自动存档已禁用")
            return
        }
        
        // 取消之前的任务
        scheduledTask?.cancel(false)
        
        val now = LocalDateTime.now()
        val targetTime = LocalTime.of(Config.autoBackupHour, Config.autoBackupMinute)
        val todayTarget = LocalDateTime.of(LocalDate.now(), targetTime)
        val nextBackup = if (now.isBefore(todayTarget)) todayTarget else todayTarget.plusDays(1)
        val initialDelay = java.time.Duration.between(now, nextBackup).toMillis()
        
        scheduledTask = scheduler.scheduleAtFixedRate(
            { executeSystemBackup() },
            initialDelay,
            TimeUnit.DAYS.toMillis(1),
            TimeUnit.MILLISECONDS
        )
        
        Ohc_login.logger.info("下次自动存档时间: $nextBackup")
    }
    
    /**
     * 设置自动存档时间
     */
    fun setAutoBackupTime(hour: Int, minute: Int): String {
        if (hour !in 0..23 || minute !in 0..59) {
            return "§c无效的时间，小时: 0-23，分钟: 0-59"
        }
        Config.autoBackupHour = hour
        Config.autoBackupMinute = minute
        Config.save()
        scheduleAutoBackup()
        return "§a自动存档时间已设置为 ${String.format("%02d:%02d", hour, minute)}"
    }
    
    /**
     * 启用/禁用自动存档
     */
    fun setAutoBackupEnabled(enabled: Boolean): String {
        Config.autoBackupEnabled = enabled
        Config.save()
        if (enabled) {
            scheduleAutoBackup()
            return "§a自动存档已启用，时间: ${String.format("%02d:%02d", Config.autoBackupHour, Config.autoBackupMinute)}"
        } else {
            scheduledTask?.cancel(false)
            scheduledTask = null
            return "§e自动存档已禁用"
        }
    }
    
    /**
     * 获取自动存档状态
     */
    fun getAutoBackupStatus(): String {
        return if (Config.autoBackupEnabled) {
            "§a自动存档: 开启\n§f时间: ${String.format("%02d:%02d", Config.autoBackupHour, Config.autoBackupMinute)}"
        } else {
            "§e自动存档: 关闭"
        }
    }
    
    /**
     * 执行系统自动存档（覆盖上一个）
     */
    private fun executeSystemBackup() {
        val srv = server ?: return
        
        Ohc_login.logger.info("开始执行系统自动存档...")
        
        srv.execute {
            createSystemBackup(srv)
        }
    }
    
    /**
     * 创建系统存档（覆盖模式）
     */
    fun createSystemBackup(server: MinecraftServer): CompletableFuture<BackupResult> {
        val targetDir = File(backupDir, SYSTEM_BACKUP_NAME)
        
        return CompletableFuture.supplyAsync({
            try {
                server.execute {
                    server.saveAll(false, true, true)
                }
                Thread.sleep(500)
                
                // 删除旧的系统存档
                if (targetDir.exists()) {
                    targetDir.deleteRecursively()
                }
                targetDir.mkdirs()
                
                val worldDir = server.getSavePath(WorldSavePath.ROOT).toFile()
                copyDirectory(worldDir, targetDir) { file ->
                    file.name != "session.lock"
                }
                
                val size = calculateDirSize(targetDir)
                val time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                Ohc_login.logger.info("系统存档完成: $time, 大小: ${formatSize(size)}")
                
                server.execute {
                    broadcastMessage(server, "§a[系统存档] §f自动存档完成！大小: §b${formatSize(size)}")
                }
                
                BackupResult(true, "系统存档成功", SYSTEM_BACKUP_NAME, size)
            } catch (e: Exception) {
                Ohc_login.logger.error("系统存档失败", e)
                BackupResult(false, "系统存档失败: ${e.message}")
            }
        }, executor)
    }
    
    /**
     * 获取所有备份列表
     */
    fun listBackups(): List<BackupInfo> {
        if (!backupDir.exists()) return emptyList()
        return backupDir.listFiles()
            ?.filter { it.isDirectory }
            ?.map { dir ->
                BackupInfo(
                    name = dir.name,
                    path = dir,
                    size = calculateDirSize(dir),
                    createdAt = dir.lastModified()
                )
            }
            ?.sortedByDescending { it.createdAt }
            ?: emptyList()
    }
    
    /**
     * 检查备份是否存在
     */
    fun backupExists(name: String): Boolean {
        return File(backupDir, name).exists()
    }
    
    /**
     * 获取备份信息
     */
    fun getBackup(name: String): BackupInfo? {
        val dir = File(backupDir, name)
        if (!dir.exists() || !dir.isDirectory) return null
        return BackupInfo(
            name = dir.name,
            path = dir,
            size = calculateDirSize(dir),
            createdAt = dir.lastModified()
        )
    }
    
    /**
     * 创建存档备份
     * @param server MinecraftServer 实例
     * @param backupName 备份名称
     * @param operatorName 操作者名称
     * @return CompletableFuture<BackupResult>
     */
    fun createBackup(
        server: MinecraftServer,
        backupName: String,
        operatorName: String
    ): CompletableFuture<BackupResult> {
        val timestamp = LocalDateTime.now().format(dateFormatter)
        val fullName = "${backupName}_$timestamp"
        val targetDir = File(backupDir, fullName)
        
        if (targetDir.exists()) {
            return CompletableFuture.completedFuture(
                BackupResult(false, "备份名称已存在: $fullName")
            )
        }
        
        // 广播开始消息
        val startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
        broadcastMessage(server, "§e[存档] §f管理员 §a$operatorName §f在 §b$startTime §f保存存档 §6$backupName")
        
        return CompletableFuture.supplyAsync({
            try {
                // 强制保存所有世界
                server.execute {
                    server.saveAll(false, true, true)
                }
                // 等待保存完成
                Thread.sleep(500)
                
                val worldDir = server.getSavePath(WorldSavePath.ROOT).toFile()
                targetDir.mkdirs()
                
                // 复制世界文件（排除 session.lock）
                copyDirectory(worldDir, targetDir) { file ->
                    file.name != "session.lock"
                }
                
                val size = calculateDirSize(targetDir)
                Ohc_login.logger.info("存档完成: $fullName, 大小: ${formatSize(size)}")
                
                BackupResult(true, "存档成功: $fullName", fullName, size)
            } catch (e: Exception) {
                Ohc_login.logger.error("存档失败", e)
                BackupResult(false, "存档失败: ${e.message}")
            }
        }, executor).thenApply { result ->
            // 广播结果
            server.execute {
                if (result.success) {
                    broadcastMessage(server, "§a[存档] §f存档 §6${result.backupName} §f完成！大小: §b${formatSize(result.size)}")
                } else {
                    broadcastMessage(server, "§c[存档] §f存档失败: ${result.message}")
                }
            }
            result
        }
    }
    
    /**
     * 热回档
     * @param server MinecraftServer 实例
     * @param backupName 备份名称
     * @param operatorName 操作者名称
     * @param delaySeconds 延迟秒数
     * @param worldType 可选：overworld/nether/end，null 表示全部恢复
     */
    fun prepareRestore(
        server: MinecraftServer,
        backupName: String,
        operatorName: String,
        delaySeconds: Int = 10,
        worldType: String? = null
    ): CompletableFuture<RestoreResult> {
        val backupDir = File(this.backupDir, backupName)
        if (!backupDir.exists() || !backupDir.isDirectory) {
            return CompletableFuture.completedFuture(
                RestoreResult(false, "找不到存档: $backupName")
            )
        }
        
        val worldDesc = when (worldType) {
            "overworld" -> "主世界"
            "nether" -> "下界"
            "end" -> "末地"
            else -> "全部世界"
        }
        
        // 广播回档消息
        broadcastMessage(server, "§c[回档] §f管理员 §a$operatorName §f使用了回档，服务器将在 §c${delaySeconds} §f秒后回档 §6$backupName §f($worldDesc)")
        
        return CompletableFuture.supplyAsync({
            try {
                // 倒计时
                for (i in delaySeconds downTo 1) {
                    if (i <= 5 || i % 5 == 0) {
                        server.execute {
                            broadcastMessage(server, "§c[回档] §f回档倒计时: §c$i §f秒...")
                        }
                    }
                    Thread.sleep(1000)
                }
                
                // 执行热回档
                val result = java.util.concurrent.CompletableFuture<RestoreResult>()
                server.execute {
                    try {
                        executeHotRestore(server, backupDir, worldType)
                        broadcastMessage(server, "§a[回档] §f回档完成！存档: §6$backupName §f($worldDesc)")
                        result.complete(RestoreResult(true, "回档完成"))
                    } catch (e: Exception) {
                        Ohc_login.logger.error("回档失败", e)
                        broadcastMessage(server, "§c[回档] §f回档失败: ${e.message}")
                        result.complete(RestoreResult(false, "回档失败: ${e.message}"))
                    }
                }
                
                result.get()
            } catch (e: Exception) {
                Ohc_login.logger.error("回档准备失败", e)
                RestoreResult(false, "回档准备失败: ${e.message}")
            }
        }, executor)
    }
    
    /**
     * 执行热回档（异步恢复文件，玩家可看到进度）
     * @param worldType 可选：overworld/nether/end，null 表示全部恢复
     */
    private fun executeHotRestore(server: MinecraftServer, backupDir: File, worldType: String?) {
        Ohc_login.logger.info("开始回档: ${backupDir.name}, 世界: ${worldType ?: "全部"}")
        
        val worldDir = server.getSavePath(WorldSavePath.ROOT).toFile()
        val worldFiles = listOf("region", "entities", "poi", "data")
        val globalFiles = listOf("level.dat", "level.dat_old")  // playerdata 单独处理
        
        // 构建恢复任务列表（不含 playerdata）
        val restoreTasks = mutableListOf<RestoreTask>()
        
        when (worldType) {
            "overworld" -> {
                (worldFiles + globalFiles).forEach { fileName ->
                    val backupFile = File(backupDir, fileName)
                    val worldFile = File(worldDir, fileName)
                    if (backupFile.exists()) {
                        restoreTasks.add(RestoreTask("主世界/$fileName", backupFile, worldFile))
                    }
                }
            }
            "nether" -> {
                val dimBackup = File(backupDir, "DIM-1")
                val dimWorld = File(worldDir, "DIM-1")
                if (dimBackup.exists()) {
                    worldFiles.forEach { fileName ->
                        val backupFile = File(dimBackup, fileName)
                        val worldFile = File(dimWorld, fileName)
                        if (backupFile.exists()) {
                            restoreTasks.add(RestoreTask("下界/$fileName", backupFile, worldFile))
                        }
                    }
                } else {
                    Ohc_login.logger.warn("备份中不存在下界数据")
                }
            }
            "end" -> {
                val dimBackup = File(backupDir, "DIM1")
                val dimWorld = File(worldDir, "DIM1")
                if (dimBackup.exists()) {
                    worldFiles.forEach { fileName ->
                        val backupFile = File(dimBackup, fileName)
                        val worldFile = File(dimWorld, fileName)
                        if (backupFile.exists()) {
                            restoreTasks.add(RestoreTask("末地/$fileName", backupFile, worldFile))
                        }
                    }
                } else {
                    Ohc_login.logger.warn("备份中不存在末地数据")
                }
            }
            else -> {
                // 主世界
                (worldFiles + globalFiles).forEach { fileName ->
                    val backupFile = File(backupDir, fileName)
                    val worldFile = File(worldDir, fileName)
                    if (backupFile.exists()) {
                        restoreTasks.add(RestoreTask("主世界/$fileName", backupFile, worldFile))
                    }
                }
                // 下界
                val netherBackup = File(backupDir, "DIM-1")
                val netherWorld = File(worldDir, "DIM-1")
                if (netherBackup.exists()) {
                    worldFiles.forEach { fileName ->
                        val backupFile = File(netherBackup, fileName)
                        val worldFile = File(netherWorld, fileName)
                        if (backupFile.exists()) {
                            restoreTasks.add(RestoreTask("下界/$fileName", backupFile, worldFile))
                        }
                    }
                }
                // 末地
                val endBackup = File(backupDir, "DIM1")
                val endWorld = File(worldDir, "DIM1")
                if (endBackup.exists()) {
                    worldFiles.forEach { fileName ->
                        val backupFile = File(endBackup, fileName)
                        val worldFile = File(endWorld, fileName)
                        if (backupFile.exists()) {
                            restoreTasks.add(RestoreTask("末地/$fileName", backupFile, worldFile))
                        }
                    }
                }
            }
        }
        
        // 异步执行恢复，玩家可以看到进度
        val total = restoreTasks.size
        broadcastMessage(server, "§e[回档] §f开始恢复文件，共 §b$total §f项...")
        
        CompletableFuture.runAsync({
            restoreTasks.forEachIndexed { index, task ->
                val progress = ((index + 1) * 100) / total
                val progressBar = buildProgressBar(progress)
                
                // 回到主线程广播进度
                server.execute {
                    broadcastMessage(server, "§e[回档] §f$progressBar §b${index + 1}/$total §7${task.name}")
                }
                
                restoreFile(task.backupFile, task.worldFile)
            }
            
            // 文件恢复完成，回到主线程踢出玩家
            server.execute {
                broadcastMessage(server, "§a[回档] §f文件恢复完成！正在断开玩家连接...")
                
                // 踢出所有玩家
                server.playerManager.playerList.toList().forEach { player ->
                    player.networkHandler.disconnect(Text.literal("§a回档完成，服务器正在重启..."))
                }
            }
            
            // 等待玩家完全断开
            Thread.sleep(500)
            
            // 恢复 playerdata（玩家已完全断开，不会被覆盖）
            val playerdataBackup = File(backupDir, "playerdata")
            val playerdataWorld = File(worldDir, "playerdata")
            if (playerdataBackup.exists()) {
                restoreFile(playerdataBackup, playerdataWorld)
                Ohc_login.logger.info("已恢复玩家位置数据: ${playerdataBackup.absolutePath} -> ${playerdataWorld.absolutePath}")
            } else {
                Ohc_login.logger.warn("备份中不存在 playerdata")
            }
            
            // playerdata 恢复完成后再重启
            server.execute {
                Ohc_login.logger.info("回档完成: ${backupDir.name}，正在重启服务器...")
                server.stop(false)
            }
        }, executor)
    }
    
    private data class RestoreTask(val name: String, val backupFile: File, val worldFile: File)
    
    private fun buildProgressBar(percent: Int): String {
        val filled = percent / 5
        val empty = 20 - filled
        return "§a" + "▌".repeat(filled) + "§7" + "▌".repeat(empty) + " §f$percent%"
    }
    
    private fun restoreFile(backupFile: File, worldFile: File) {
        try {
            if (worldFile.exists()) {
                if (worldFile.isDirectory) {
                    worldFile.deleteRecursively()
                } else {
                    worldFile.delete()
                }
            }
            
            if (backupFile.isDirectory) {
                copyDirectory(backupFile, worldFile)
            } else {
                worldFile.parentFile?.mkdirs()
                Files.copy(backupFile.toPath(), worldFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
            }
            Ohc_login.logger.debug("已恢复: ${backupFile.name}")
        } catch (e: Exception) {
            Ohc_login.logger.warn("恢复文件失败: ${backupFile.name} - ${e.message}")
        }
    }
    
    private data class PlayerPosition(
        val world: RegistryKey<World>,
        val x: Double,
        val y: Double,
        val z: Double,
        val yaw: Float,
        val pitch: Float
    )
    
    /**
     * 删除备份
     */
    fun deleteBackup(name: String): Boolean {
        val dir = File(backupDir, name)
        if (!dir.exists()) return false
        return dir.deleteRecursively()
    }
    
    /**
     * 广播消息到所有玩家
     */
    private fun broadcastMessage(server: MinecraftServer, message: String) {
        server.playerManager.broadcast(Text.literal(message), false)
    }
    
    /**
     * 复制目录
     */
    private fun copyDirectory(source: File, target: File, filter: (File) -> Boolean = { true }) {
        if (!source.exists()) return
        
        source.walkTopDown()
            .filter(filter)
            .forEach { file ->
                val relativePath = file.relativeTo(source)
                val targetFile = File(target, relativePath.path)
                
                if (file.isDirectory) {
                    targetFile.mkdirs()
                } else {
                    targetFile.parentFile?.mkdirs()
                    Files.copy(file.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
                }
            }
    }
    
    /**
     * 计算目录大小
     */
    private fun calculateDirSize(dir: File): Long {
        if (!dir.exists()) return 0
        return dir.walkTopDown()
            .filter { it.isFile }
            .sumOf { it.length() }
    }
    
    /**
     * 格式化文件大小
     */
    private fun formatSize(bytes: Long): String {
        return when {
            bytes >= 1024 * 1024 * 1024 -> String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024))
            bytes >= 1024 * 1024 -> String.format("%.2f MB", bytes / (1024.0 * 1024))
            bytes >= 1024 -> String.format("%.2f KB", bytes / 1024.0)
            else -> "$bytes B"
        }
    }
    
    data class BackupInfo(
        val name: String,
        val path: File,
        val size: Long,
        val createdAt: Long
    )
    
    data class BackupResult(
        val success: Boolean,
        val message: String,
        val backupName: String? = null,
        val size: Long = 0
    )
    
    data class RestoreResult(
        val success: Boolean,
        val message: String
    )
}
